#ifndef ACTIONCOMMANDS_H
#define ACTIONCOMMANDS_H

#include "global.h"
#include "command.h"
#include "robotaction.h"

/**
 * @brief Defines the interface for a command that manipulates a robot action.
 * Inherits Command.
 *
 */
class ActionCommand: public Command{
protected:
    /**
     * @brief The RobotAction object that receives this command.
     *
     */
    RobotAction* _action;

public:
    /**
     * @brief Constructor.  Creates a new Action command.  The command needs to know
     * what RobotAction object it is affecting.
     *
     * @param action The RobotAction this command affects.
     */
    ActionCommand(RobotAction* action);
    virtual void execute() = 0;
    virtual void undo() = 0;
};


/************************************************************/
/*                ACTION COMMAND GROUP CLASS                */
/************************************************************/
/**
 * @brief Used to group several action commands together. Inherits ActionCommand.
 *
 */
class ActionCommandGroup: public ActionCommand{
private:
    QList<ActionCommand*> _commandList;

public:
    ActionCommandGroup(RobotAction* action);

    void execute();
    void undo();
    void append(ActionCommand* command);
};


/************************************************************/
/*              INSERT KEY FRAME COMMAND CLASS              */
/************************************************************/
/**
 * @brief Inserts a motion key frame into the action.  Inherits ActionCommand.
 *
 * The position of the joints are interpolated.
 *
 */
class InsertKeyFrameCommand: public ActionCommand{
private:
    int _timestamp, _jointID;
    bool _joint;
    float _insertedValue;
    MotionKeyFrame _insertedFrame;

public:
    /**
     * @brief Constructor.  Creates a new InsertKeyFrameCommand that inserts key frames
     * for every joint of the action.
     *
     * @param action The action to modify.
     * @param msec The timestamp where the key frame is to be inserted.
     */
    InsertKeyFrameCommand(RobotAction* action, int msec);
    /**
     * @brief Constructor.  Creates a new InsertKeyFrameCommand that inserts a key frame
     * for a specific joint of the action.
     *
     * @param action The action to modify.
     * @param msec The timestamp where the key frame is to be inserted.
     * @param jointID The joint for which the key frame is to be inserted.
     */
    InsertKeyFrameCommand(RobotAction* action, int msec, int jointID);

    void execute();
    void undo();
};


/************************************************************/
/*              SET ROBOT JOINT COMMAND CLASS               */
/************************************************************/
class DeleteKeyFrameCommand: public ActionCommand{
private:
    int _timestamp, _jointID;
    bool _joint;
    float _deletedValue;
    MotionKeyFrame _deletedFrame;

public:
    DeleteKeyFrameCommand(RobotAction* action, int msec);
    DeleteKeyFrameCommand(RobotAction* action, int msec, int jointID);
    void execute();
    void undo();
};


/************************************************************/
/*              SET ROBOT JOINT COMMAND CLASS               */
/************************************************************/
class MoveKeyFrameCommand: public ActionCommand{
private:
    int _timestamp, _newTimestamp, _jointID;
    bool _joint;

public:
    MoveKeyFrameCommand(RobotAction* action, int msec, int newMsec);
    MoveKeyFrameCommand(RobotAction* action, int msec, int jointID, int newMsec);
    void execute();
    void undo();
};


/************************************************************/
/*              SET ROBOT JOINT COMMAND CLASS               */
/************************************************************/
class SetKeyFrameCommand: public ActionCommand{
private:
    int _timestamp, _jointID;
    float _theta, _prevTheta;

public:
    SetKeyFrameCommand(RobotAction* action, int msec, int jointID, float theta);
    void execute();
    void undo();
};


/************************************************************/
/*              SET ROBOT JOINT COMMAND CLASS               */
/************************************************************/
class SetSoundCommand: public ActionCommand{
private:
    int _timestamp;
    QString _filename;
    SoundInfo _prevSound;

public:
    SetSoundCommand(RobotAction* action, int msec, QString filename);
    void execute();
    void undo();
};


/************************************************************/
/*              SET ROBOT JOINT COMMAND CLASS               */
/************************************************************/
class DeleteSoundCommand: public ActionCommand{
private:
    int _timestamp;
    QString  _deletedFilename;
    SoundInfo _deletedSound;

public:
    DeleteSoundCommand(RobotAction* action, int msec);
    void execute();
    void undo();
};


/************************************************************/
/*              SET ROBOT JOINT COMMAND CLASS               */
/************************************************************/
class MoveSoundCommand: public ActionCommand{
private:
    int _timestamp, _newTimestamp;

public:
    MoveSoundCommand(RobotAction* action, int msec, int newMsec);
    void execute();
    void undo();
};


/************************************************************/
/*              SET ROBOT JOINT COMMAND CLASS               */
/************************************************************/
class TrimSoundCommand: public ActionCommand{
private:
    int _timestamp, _frontTrim, _backTrim;

public:
    TrimSoundCommand(RobotAction* action, int msec, int frontTrim, int backTrim);
    void execute();
    void undo();
};

#endif // ACTIONCOMMANDS_H
